{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Chapter 14: Reading and writing text files\n", "*We use some materials from [this other Python course](https://github.com/kadarakos/python-course).*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this chapter, you will learn how to read data from files, do some analysis, and write the results to disk. \n", "\n", "Reading and writing files are quite an essential part of programming, as it is the first step for your program to communicate with the outside world. In most cases, you will write programs that take data from some source, manipulates it in some way, and writes some results out somewhere. \n", "\n", "For example, if you would write a survey, you could take input from participants on a webserver and save their answers in some files or in a database. When the survey is over, you would read these results in and do some analysis on the data you have collected, maybe do some visualizations and save your results.\n", "\n", "In **Natural Language Processing (NLP)**, you often process files containing raw texts with some code and write the results to some other file. \n", "\n", "### At the end of this chapter, you will be able to:\n", "\n", "* open one or multiple text files\n", "* work with the modules `os` and `glob`\n", "* read the contents of a file\n", "* write new or manipulated content to new (or existing) files\n", "* close a file\n", "\n", "\n", "### If you want to learn more about these topics, you might find the following links useful:\n", "\n", "* [Video: File Objects - Reading and Writing to Files](https://www.youtube.com/watch?v=Uh2ebFW8OYM)\n", "* [Video: Automate Parsing and Renaming of Multiple Files](https://www.youtube.com/watch?v=ve2pmm5JqmI)\n", "* [Video: OS Module - Use Underlying Operating System Functionality](https://www.youtube.com/watch?v=tJxcKyFMTGo)\n", "* [Blog post: 6 Ways the Linux File System is Different From the Windows File System](http://www.howtogeek.com/137096/6-ways-the-linux-file-system-is-different-from-the-windows-file-system/) \n", "\n", "If you have **questions** about this chapter, please contact us **(cltl.python.course@gmail.com)**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Reading a file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python, you can read the content of a file, store it as the type of object that you need (string, list, etc.) and manipulate it (e.g., replacing or removing words). You can also write new content to an existing or a new file.\n", "\n", "Here, we will discuss how to:\n", "\n", "* open a file\n", "* read in the content\n", "* store the context in a variable (to do something), e.g., as a string or list\n", "* close the file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.1. File paths" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To open a file, we need to associate the file on disk with a variable in Python. First, we tell Python **where the file is stored on your disk**. The **location of your file** is often referred to as the **file path**. \n", "\n", "Python will start looking in the 'working' or 'current' directory (which often will be where your Python script is). If it's in the working directory, you only have to tell Python the name of the file (e.g., `charlie.txt`). If it's not in the working directory, as in our case, you have to tell Python the exact path to your file. We will create a string variable to store this information:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filename = \"../Data/Charlie/charlie.txt\" \n", "\n", "# The double dots mean 'go up one level in the directory tree'. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes you see double dots at the beginning of the file path; this means 'the parent of the current directory'. When writing a file path, you can use the following:\n", "\n", "- / means the root of the current drive; \n", "- ./ means the current directory;\n", "- ../ means the parent of the current directory.\n", "\n", "Consider the directory tree below. \n", "\n", "* If you want to go from your current working directory (**cwd**) to the one directly above (dir3), your path is ../. \n", "* If you want to go to dir1, your path is ../../\n", "* If you want to go to dir5, your path is ../dir5/\n", "* If you want to go to dir2, your path is ../../dir2/ \n", "\n", "You will learn how to navigate your directory tree quite intuitively with a bit of practice. If you have any doubts, it is always a good idea to follow a quick tutorial on basic command-line operations. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Navigating your directory tree on Windows**\n", "\n", "Also, note that the formatting of file paths is different across operating systems. The file path, as specified above, should work on any UNIX platform (Linux, Mac). If you are using Windows, however, you might run into problems when formatting file paths in this way **outside of this notebook**, because Windows uses backslashes instead of forward slashes (Jupyter Notebook should already have taken care of these problems for you). In that case, it might be useful to have a look at [this page](http://www.howtogeek.com/137096/6-ways-the-linux-file-system-is-different-from-the-windows-file-system/) about the differences between the file systems. In short, it's probably best if you use the code below (we will talk about the `os` module in more detail later today). This is very useful to know if you are a Windows user, and it will become relevant for the final assignment. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# For windows: \n", "import os\n", "windows_file_path = os.path.normpath(\"C:/somePath/someFilename\") # Use forward slashes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.2 Opening a file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use the file path to tell Python which file to open by using the built-in function `open()`. The `open()` function does not return the actual text that is saved in the text file. It returns a 'file object' from which we can read the content using the `.read()` function (more on this later). We usually pass three arguments to the `open()` function:\n", "\n", "* the **path to the file** that you wish to open\n", "* the **mode**, a combination of characters explaining the purpose of the file opening (like read or write) and type of content stored in the file (like textual or binary format). For instance, if we are reading a plain text file, we can use the characters 'r' (represents read-mode) and 't' (represents plain text-mode).\n", "* the last argument, a keyword argument (**encoding**), specifies the encoding of the text file, but you can forget about this for now.\n", "\n", "The most important **mode** arguments the `open()` function can take are:\n", "\n", "* **r** = Opens a file for reading only. The file pointer is placed at the beginning of the file.\n", "* **w** = Opens a file for writing only. Overwrites the file if the file exists. If the file does not exist, creates a new file for writing.\n", "* **a** = Opens a file for appending. The file pointer is at the end of the file if the file exists. If the file does not exist, it creates a new file for writing. Use it if you would like to add something to the end of a file\n", "\n", "Then, to open the file 'charlie.txt' for reading purposes, we use the following:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\" \n", "infile = open(filepath, \"r\") # 'r' stands for READ mode\n", "# Do something with the file\n", "infile.close() # Close the file (you can ignore this for now)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Overview of possible mode arguments (the most important ones are 'r' and 'w'):\n", "\n", "| Character | Meaning |\n", "| --------- | ------- |\n", "|'r' |\topen for reading (default)|\n", "|'w' |\topen for writing, truncating the file first|\n", "|'x' |\topen for exclusive creation, failing if the file already exists|\n", "|'a' |\topen for writing, appending to the end of the file if it exists|\n", "|'b' |\tbinary mode|\n", "|'t' |\ttext mode (default)|\n", "|'+' |\topen a disk file for updating (reading and writing)|\n", "|'U' |\tuniversal newlines mode (deprecated)|\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So far, we have opened the file. This, however, does not yet show us the file content. Try printing 'infile':" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "infile = open(\"../Data/Charlie/charlie.txt\" , \"r\")\n", "print(infile)\n", "infile.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This `TextIOWrapper` thing is Python's way of saying it has *opened* a connection to the file `charlie.txt`. To actually see its content, we need to tell python to read the file." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3 Reading a file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, we will discuss three ways of reading the contents of a file:\n", "\n", "* `read()`\n", "* `readlines()` \n", "* `readline()`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.3.1 `read()`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `read()` method is used to access the **entire text in a file**, which we can assign to a variable. Consider the code below.\n", "\n", "The variable `content` now holds the entire content of the file `charlie.txt` as a single string, and we can access and manipulate it just like any other string. When we are done with accessing the file, we use the `close()` method to close the file." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Opening the file using the filepath and and the 'read' mode:\n", "infile = open(\"../Data/Charlie/charlie.txt\" , \"r\")\n", "# Reading the file using the `read()` function and assigning it to the variable `content`\n", "content = infile.read()\n", "print(content)\n", "print()\n", "print('This function returns a', type(content))\n", "\n", "# closing the file (more on this below)\n", "infile.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.3.2 `readlines()`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `readlines()` function allows you to access the content of a file as a list of lines. This means, it splits the text in a file at the new lines characters ('\\n') for you):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Opening the file using the filepath and and the 'read' mode:\n", "infile = open(\"../Data/Charlie/charlie.txt\" , \"r\")\n", "\n", "# Reading the file using the `read()` function and assigning it to the variable `content`\n", "lines = infile.readlines()\n", "print(lines)\n", "print()\n", "print('This function returns a', type(lines))\n", "\n", "# closing the file \n", "infile.close()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now you can, for example, use a for-loop to print each line in the file (note that the second line is just a newline character):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for line in lines:\n", " print(\"LINE:\", line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Important note**\n", "\n", "When we open a file, we can only use one of the read operations **once**. If we want to read it again, we have to open a new file variable. Consider the code below:\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "infile = open(\"../Data/Charlie/charlie.txt\" , \"r\")\n", "content = infile.read()\n", "lines = infile.readlines()\n", "print(content)\n", "print(lines)\n", "infile.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The code returns an empty list. To fix this, we have to open the file again:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "infile = open(filepath , \"r\")\n", "content = infile.read()\n", "infile = open(filepath, \"r\")\n", "lines = infile.readlines()\n", "print(content)\n", "print(lines)\n", "infile.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.3.3 `Readline()`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The third operation `readline()` returns the next line of the file, returning the text up to and including the next newline character (*\\n*, or *\\r\\n* on Windows). More simply put, this operation will read a file line-by-line. So if you call this operation again, it will return the next line in the file. Try it out below!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "infile = open(filepath, \"r\")\n", "next_line = infile.readline()\n", "print(next_line)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "next_line = infile.readline()\n", "print(next_line)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "next_line = infile.readline()\n", "print(next_line)\n", "infile.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Which function to choose**\n", "\n", "For small files that you want to load entirely, you can use one of these three methods (readline, read, or readlines). Note, however, that we can also simply do the following to read a file line by line (this is recommended for larger files and when we are really only interested in a small portion of the file):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "infile = open(filepath, \"r\")\n", "for line in infile:\n", " print(line)\n", "infile.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the last line of this code snippet: `infile.close()`. This closes our file, which is a very important operation. This prevents Python from keeping files that are unnecessary anymore still open. In the next subchapter, we will also see a more convenient way to ensure files get closed after their usage." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.4. Closing the file\n", "\n", "Here, we will introduce closing a file with the method `close()` and using a **context manager** to open and close files. After reading the contents of a file, the `TextWrapper` no longer needs to be open since we have stored the content as a variable. In fact, it is good practice to close the file as soon as you do not need it anymore." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.4.1 `close()`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " We do this by using the `close()` method as already shown several times above." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "# open file\n", "infile = open(filepath , \"r\")\n", "\n", "# assign content to a varialbe\n", "content = infile.read()\n", "\n", "# close file\n", "infile.close()\n", "\n", "\n", "# do whatever you want with the context, e.g. print it:\n", "\n", "print(content)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.4.2 Using a context manager" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is actually an easier (and preferred) way to make sure that the file is closed as soon as you don't need it anymore, namely using what is called a **context manager**. Instead of using `open()` and `close()`, we use the syntax shown below. \n", "\n", "The main advantage of using the with-statement is that it automatically closes the file once you leave the local context defined by the indentation level. If you 'manually' open and close the file, you risk forgetting to close the file. Therefore, context managers are considered a best-practice, and we will use the with-statement in all of our following code. \n", "\n", "\n", "**From now on, we highly recommend using a context manager in your code.**" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "with open(filepath, \"r\") as infile:\n", " # the file is only open here\n", " # get content while file is open\n", " content = infile.read()\n", " \n", "# the context manager took care of closing the file again\n", "# we can now work with the content without having to worry about \n", "# closing the file\n", " \n", "print(content)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2 Manipulating file content" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once your file content is loaded in a Python variable, you can manipulate its content as you can manipulate any other variable. You can edit it, add/remove lines, count word occurrences, etc. Let's say we read the file content in a list of its lines, as shown below. Note that we can use all of the different methods for reading files in the context manager. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "with open(filepath, \"r\") as infile:\n", " lines = infile.readlines()\n", " \n", "print(lines)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can for instance preserve only the first 2 lines of the file, in a new variable:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "first_two_lines=lines[:2]\n", "first_two_lines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can count the lines that are longer than 15 characters:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "counter=0\n", "for line in lines:\n", " if len(line)>15:\n", " counter+=1\n", "print(counter)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will soon see how to perform text processing once we have loaded the file, by using an external module in the next chapter. But let's first write store the modified text in a new file to preserve the changes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3 Writing files" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To write content to a file, we can open a new file and write the text to this file by using the **`write()`** method. Again, we can do this by using the context manager. Remember that we have to specify the **mode** using **`w`**. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's first slightly adapt our Charlie story by replacing the names in the text:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filepath = \"../Data/Charlie/charlie.txt\"\n", "\n", "# read in file and assign content to the variable content\n", "with open(filepath, \"r\") as infile:\n", " content = infile.read()\n", " \n", "# manipulate content\n", "\n", "your_name = \"x y\" #type in your name \n", "friends_name = \"a b\" #type in the name of a friend \n", "\n", "# Replace all instances of Charlie Bucket with your name and save it in new_content\n", "new_content = content.replace(\"Charlie Bucket\", your_name)\n", "\n", "# Replace all instancs of Mr Wonka with your friends name and save it in new_new_content\n", "new_new_content = new_content.replace(\"Mr Wonka\", friends_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now save the manipulated content to a new file: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "filename = \"../Data/Charlie/charlie_new.txt\"\n", "with open(filename, \"w\") as outfile:\n", " outfile.write(new_new_content)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Open the file `charle_new.txt` in the folder `../Data/Charlie` in any text editor and read a personalized version of the story!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note about append mode (`a`):** \n", "\n", "The third mode of opening a file is *append* ('a'). If the file 'charlie_new.txt' does not exist, then append and write act the same: they create this new file and fill it with content. The difference between write and append occurs when this file would exist. In that case, the write mode overwrites its content, while the append mode adds the new content at the end of the existing one." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4 Reading and writing multiple files" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You will often have multiple files to work with. The folder ../Data/Dreams contains 10 text files describing dreams of Vickie, a 10-year-old girl. These texts are extracted from [DreamBank](http://www.dreambank.net/).\n", "\n", "To process multiple files, we often want to *iterate* over a list of files. These files are usually stored in one or multiple directories on your computer.\n", "\n", "Instead of writing out every single file path, it is much more convenient to iterate over all the files in the directory `../Data/Dreams`. So we need to find a way to tell Python: \"I want to do something with all these files at this location!\" \n", "\n", "There are two modules which make dealing with multiple files a lot easier. \n", "\n", "* glob\n", "* os\n", "\n", "We will introduce them below. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4.1 The `glob` module" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `glob` module is very useful to find all the pathnames matching a specified pattern according to the rules used by the Unix shell. You can use two wildcards: the asterisk (`*`) and the question mark (`?`). An asterisk matches zero or more characters in a segment of a name, while the question mark matches a single character in a segment of a name.\n", "\n", "For example, the following code gives all filenames in the directory `../Data/dreams`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import glob" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for filename in glob.glob(\"../Data/Dreams/*\"):\n", " print(filename)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we only want to consider text files and ignore everything else (here a file called 'IGNORE_ME!'), we can specify this in our search by only looking for files with the extension `.txt`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for filename in glob.glob(\"../Data/Dreams/*.txt\"):\n", " print(filename)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A question mark (`?`) matches any single character in that position in the name. For example, the following code prints all filenames in the directory `../Data/dreams` that start with 'vickie' followed by exactly 1 character and end with the extension `.txt` (note that this will not print `vickie10.txt`):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for filename in glob.glob(\"../Data/Dreams/vickie?.txt\"):\n", " print(filename)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also find filenames recursively by using the pattern `**` (the keyword argument `recursive` should be set to `True`), which will match any files and zero or more directories and subdirectories. The following code prints all files with the extension `.txt` in the directory `../Data/` and in all its subdirectories:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for filename in glob.glob(\"../Data/**/*.txt\", recursive=True):\n", " print(filename)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4.2 The `os` module" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another module that you will frequently see being used in examples is the `os` module. The `os` module has many features that can be very useful and which are not supported by the `glob` module. We will not go over each and every useful method here, but here's a list of some of the things that you can do (some of which we have seen above): \n", "\n", "- creating single or multiple directories: `os.mkdir()`, `os.mkdirs()`;\n", "- removing single or multiple directories: `os.rmdir()`, `os.rmdirs()`;\n", "- checking whether something is a file or a directory: `os.path.isfile()`, `os.path.isdir()`;\n", "- split a path and return a tuple containing the directory and filename: `os.path.split()`;\n", "- construct a pathname out of one or more partial pathnames: `os.path.join()`\n", "- split a filename and return a tuple containing the filename and the file extension: `os.path.splitext()`\n", "- get only the basename or the directory path: `os.path.basename()`, `os.path.dirname()`.\n", "\n", "Feel free to play around with these methods and figure out how they work yourself :-) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Start by importing the module:\n", "import os\n", "\n", "# let's use a filepath for testing it out:\n", "filepath = \"../Data/Charlie/charlie.txt\"\n", "os.path.basename(filepath)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Exercises" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exercise 1:** \n", "\n", "Write a program that opens `RedCircle.txt` in the `../Data/RedCircle` folder and prints its content as a single string:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exercise 2:** \n", "\n", "Write a program that opens `RedCircle.txt` in the `../Data/RedCircle` folder and prints a list containing all lines in the file:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exercise 3:** \n", "\n", "Create a counter dictionary like in block 2 (the dictionaries chapter), where you will count the number of occurences of each word in a file." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Exercise 4:** \n", "\n", "The module `os` implements functions that allow us to work with the operating system (see folder contents, change directory, etc.). Use the function `listdir` from the module `os` to see the contents of the current directory. Then print all the items that do not start with a dot." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your code here" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.4" } }, "nbformat": 4, "nbformat_minor": 4 }